/**
 * Copyright 2008-2009. 重庆富邦科技发展有限公司, Inc. All rights reserved.
 * <a>http://www.3gcq.cn</a>
 */
package com.fbty.base.orm.jdbc;

import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.util.Assert;

import com.fbty.base.domain.Page;
import com.fbty.base.orm.SqlUtils;

/**
 * <p>Title: </p>
 * <p>Description: 定义支持数据库mysql 的分页方法</p>
 * <p>Company:重庆富邦科技发展有限责任公司 </p>
 * @author liyun create 2010-4-11
 * @version 0.1
 *
 */
public class MysqlJdbcTemplate extends BaseJdbcTemplate {
	
	protected final Log log = LogFactory.getLog(MysqlJdbcTemplate.class);

	public MysqlJdbcTemplate(DataSource dataSource) {
		super(dataSource);
		this.jdbcTemplate = (JdbcTemplate) this.getJdbcOperations();
	}
	
	
	public MysqlJdbcTemplate(JdbcOperations classicJdbcTemplate) {
		super(classicJdbcTemplate);
		this.jdbcTemplate = (JdbcTemplate) this.getJdbcOperations();
	}
	
	/**
	 * 
	 * Description: 如果事先定义有POJO类，返回的数据也希望是封装好的数据请使用该方法<br>
	 * 该方法支持预编译的SQL语句。
	 * @param sql          带?的预编译SQL语句
	 * @param requiredType 返回数据的泛型
	 * @param pageNo       返回第几页的数据
	 * @param pageSize     返回数据每页多少行数据
	 * @param args         预编译参数,未限定个数
	 * @return
	 */
	public Page queryPage(String sql, Class<?> requiredType, int pageNo,int pageSize,Object... args){
		
		Assert.notNull(sql, "SQL must not be null");
		
		String countSqlString = "select count(*) " + SqlUtils.removeSelect(SqlUtils.removeOrders(sql));
		int totalCount = queryForInt(countSqlString, args);
		
		if (totalCount < 1) {
			return new Page();
		}
		
		String sqlLimit = getLimitString(sql,pageNo,pageSize);
		
		ParameterizedRowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(requiredType);
		List<?> list = query(sqlLimit, rm, args);
		
		return new Page(list,Page.getStartOfPage(pageNo, pageSize),pageNo,pageSize);
	}
	
	
	/**
	 * 
	 * Description: 如果事先定义有POJO类，返回的数据也希望是封装好的数据请使用该方法<br>
	 * @param sql          查询SQL语句
	 * @param requiredType 返回数据的泛型
	 * @param pageNo       返回第几页的数据
	 * @param pageSize     返回数据每页多少行数据
	 * @param fiter        过滤条件 key为要过滤的字段，value为需要过滤的值
	 * @return
	 */
	public Page queryPage(String sql, Class<?> requiredType, int pageNo,int pageSize,Map<String, String> fiter){
		
		Assert.notNull(sql, "SQL must not be null");
		
		String countSqlString = "select count(*) " + SqlUtils.removeSelect(SqlUtils.removeOrders(sql));
		int totalCount = queryForInt(countSqlString, fiter);
		
		if (totalCount < 1) {
			return new Page();
		}
		
		String sqlLimit = getLimitString(sql,pageNo,pageSize);
		
		ParameterizedRowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(requiredType);
		List<?> list = query(sqlLimit, rm, fiter);
		
		return new Page(list,Page.getStartOfPage(pageNo, pageSize),pageNo,pageSize);
	}
	
	/**
	 * 
	 * Description: 用于查询返回的是map list时候的分页，args为预处理值，根据SQL预处理的<br>
	 *              例如： select * from tab_test where  column1 = ?, column2 = ?,column3 = ?  args=[1,2,3]
	 * @param sql       查询SQL，可以为带?的预处理SQL语句
	 * @param pageNo    当前页
	 * @param pageSize  每页显示的行数
	 * @param args      values 可变参数 用户可以由以下几种方式使用:<br>
	 * 					第一种，未有?预编译的情况  queryPageMap(sql,pageNo,pageSize);<br> 
	 * 					第二种，一个条件参数的情况 queryPageMap(sql,pageNo,pageSize,arg0);<br>
	 *					第三种，N个条件参数的情况 queryPageMap(sql,pageNo,pageSize,arg0,arg1,arg2...argN);具体数目应当和SQL语句?个数一致<br>
	 *					第四种，使用数组作为参数  queryPageMap(sql,pageNo,new Object[arg0,arg1,arg2])<br>
	 * @return  
	 */
	public Page queryPageMap(String sql,int pageNo,int pageSize,Object...args){
		
		Assert.notNull(sql, "SQL must not be null");
		
		String countSqlString = "select count(*) " + SqlUtils.removeSelect(SqlUtils.removeOrders(sql));
		int totalCount = queryForInt(countSqlString, args);
		
		if (totalCount < 1) {
			return new Page();
		}
		
		String sqlLimit = getLimitString(sql,pageNo,pageSize);
		
		List<Map<String, Object>> list = queryForList(sqlLimit, args);
		return new Page(list,Page.getStartOfPage(pageNo, pageSize),totalCount,pageSize);
	}
	
	
	/**
	 * 
	 * Description: 用于查询返回的是map list时候的分页，filter为查询条件<br>
	 *              key为需要设置条件的数据库字段，value为设置条件值<br>
	 * @param sql   查询SQL
	 * @param pageNo    当前页
	 * @param pageSize  每页显示的行数
	 * @param fiter     过滤条件  例如 select * from tab_test where column1 = 1;   fiter = {key=column1,value=1}
	 * @return  
	 */
	public Page queryPageMap(String sql,int pageNo,int pageSize,Map<String, String> fiter){
		
		Assert.notNull(sql, "SQL must not be null");
		
		String countSqlString = "select count(*) " + SqlUtils.removeSelect(SqlUtils.removeOrders(sql));
		int totalCount = queryForInt(countSqlString, fiter);
		
		if (totalCount < 1) {
			return new Page();
		}
		
		String sqlLimit = getLimitString(sql,pageNo,pageSize);
		
		List<Map<String, Object>> list = queryForList(sqlLimit, fiter);
		return new Page(list,Page.getStartOfPage(pageNo, pageSize),pageNo,pageSize);
	}
	
	
	/**
	 * 
	 * Description: <br>
	 * @param sql
	 * @param args
	 * @return
	 */
	public List queryList(String sql,Class<?> clazz,Object...args){
		
		ParameterizedRowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(clazz);
		List<?> list = query(sql, rm, args);
		return list;
	}
	
	/**
	 * 
	 * Description: <br>
	 * @param sql
	 * @param requiredType
	 * @param fiter
	 * @return
	 */
	public List queryList(String sql,Class<?> clazz,Map<String, String> fiter){
		
		ParameterizedRowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(clazz);
		List<?> list = query(sql, rm, fiter);
		return list;
	}
	
	
	/**
	 * 
	 * Description: mysql 分页处理类<br>
	 * @param sql
	 * @param pageNo
	 * @param pageSize
	 * @return
	 */
	public  String  getLimitString(String  sql,int pageNo,int pageSize)  {
		StringBuffer  pagingSelect  =  new  StringBuffer(100);
		int firtRow = (pageNo - 1) * pageSize;
		
		pagingSelect.append(sql);
		pagingSelect.append(" limit "+firtRow+", "+pageSize);
		if(log.isDebugEnabled()){
			log.debug("query sql is "+pagingSelect);
		}
		return  pagingSelect.toString();
	}
	
}
